package com.whoyx.jiebing.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.whoyx.jiebing.dao.entity.MsgConversationEntity;
import com.whoyx.jiebing.dao.entity.MsgRecordEntity;
import com.whoyx.jiebing.dao.entity.UserEntity;
import com.whoyx.jiebing.dao.entity.UserServiceWordEntity;
import com.whoyx.jiebing.dao.service.IMsgConversationService;
import com.whoyx.jiebing.dao.service.IMsgRecordService;
import com.whoyx.jiebing.dao.service.IUserService;
import com.whoyx.jiebing.dao.service.IUserServiceWordService;
import com.whoyx.jiebing.domain.BasePageReqDto;
import com.whoyx.jiebing.domain.enums.DeleteEnum;
import com.whoyx.jiebing.domain.enums.MsgTypeEnum;
import com.whoyx.jiebing.domain.msg.CallbackStateChangeBo;
import com.whoyx.jiebing.domain.msg.MsgBody;
import com.whoyx.jiebing.domain.msg.bo.*;
import com.whoyx.jiebing.domain.msg.req.MsgUserRegisterReqDto;
import com.whoyx.jiebing.domain.msg.req.TimAdminSendMsgData;
import com.whoyx.jiebing.domain.msg.resp.InitConversationRespDto;
import com.whoyx.jiebing.domain.msg.resp.MsgDataRespDtoV2;
import com.whoyx.jiebing.domain.msg.resp.TimResultMsg;
import com.whoyx.jiebing.domain.msg.resp.UserSigRespDto;
import com.whoyx.jiebing.domain.req.MsgRecordPageReqDto;
import com.whoyx.jiebing.domain.req.ServiceInitReqDto;
import com.whoyx.jiebing.domain.resp.DoctorInfoRespDto;
import com.whoyx.jiebing.domain.resp.PatientBaseInfoRespDto;
import com.whoyx.jiebing.domain.resp.ServiceInitRespDto;
import com.whoyx.jiebing.domain.resp.UploadUrlRespDto;
import com.whoyx.jiebing.service.AsyncService;
import com.whoyx.jiebing.service.HospitalServiceClient;
import com.whoyx.jiebing.service.MsgService;
import com.whoyx.jiebing.service.PatientService;
import com.whoyx.jiebing.utils.*;
import com.whoyx.jiebing.utils.nlp.NlpUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class MsgServiceImpl implements MsgService {
    private final IMsgRecordService iMsgRecordService;
    private final IUserService iUserService;
    private final HospitalServiceClient hospitalServiceClient;
    private final PatientService patientService;
    private final IMsgConversationService iMsgConversationService;
    private final IUserServiceWordService iUserServiceWordService;
    private final NlpUtils nlpUtils;
    private final AsyncService asyncService;

    private static final String BASE_SINGLE_IMPORT_URL = "https://console.tim.qq.com/v4/im_open_login_svc/account_import?";
    private static final String BASE_ADMIN_SEND_MSG_URL = "https://console.tim.qq.com/v4/openim/sendmsg?";
    @Value("${tim.secret}")
    private String timSecret;
    @Value("${tim.appId}")
    private Long timAppId;
    @Value("${tim.serviceUid}")
    private String serviceUid;
    @Value("${third.debug}")
    private boolean thirdDebug;

    @Value("${tim.serviceAvatar}")
    private String SERVICE_AVATAR;
    private String DOCTOR_AVATAR = "";

    @Override
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public ServiceInitRespDto serviceInit(ServiceInitReqDto reqDto) {

        // todo 医生写死一个openId

        if (reqDto.getRole() == 1) {
            reqDto.setOpenId("o6fsjuEOWoDhD9ipJ6Alzz8cwbmw");
        }

        UserEntity userEntity = iUserService.getByOpenId(reqDto.getOpenId());
        if (userEntity == null) {
            // im系统注册用户
            register(MsgUserRegisterReqDto.builder()
                    .openId(reqDto.getOpenId())
                    .role(reqDto.getRole())
                    .build());
        } else if (!userEntity.getUserRole().equals(reqDto.getRole())) {
            throw new BaseException(403, "用户角色不正确");
        }
        userEntity = iUserService.getByOpenId(reqDto.getOpenId());
        StpUtil.login(userEntity.getUid());
        String token = StpUtil.getTokenValue();
        return ServiceInitRespDto.builder()
                .openId(reqDto.getOpenId())
                .uid(userEntity.getUid())
                .token(token)
                .build();
    }

    @Override
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public void callBack(Object obj) {
        JSONObject jsonObject = JSONUtil.parseObj(obj);
        String callbackCommand = jsonObject.getStr("CallbackCommand");
        switch (callbackCommand) {
            case "C2C.CallbackAfterSendMsg":
                // 发单聊消息之后回调
                CallbackAfterSendMsgBo callbackAfterSendMsgBo = jsonObject.toBean(CallbackAfterSendMsgBo.class);
                callbackAfterSendMsg(callbackAfterSendMsgBo);
                break;
            case "C2C.CallbackAfterMsgWithDraw":
                // 消息撤回回调
                CallbackAfterMsgWithDrawBo callbackAfterMsgWithDrawBo = jsonObject.toBean(CallbackAfterMsgWithDrawBo.class);
                callbackAfterMsgWithDraw(callbackAfterMsgWithDrawBo);
                break;
            case "State.StateChange":
                // 用户登录状态改变回调
                CallbackStateChangeBo callbackStateChangeBo = jsonObject.toBean(CallbackStateChangeBo.class);
                callbackStateChange(callbackStateChangeBo);
                break;
            case "C2C.CallbackAfterMsgReport":
                // 消息已读上报后回调
                CallbackAfterMsgReportBo callbackAfterMsgReportBo = jsonObject.toBean(CallbackAfterMsgReportBo.class);
                callbackAfterMsgReport(callbackAfterMsgReportBo);
                break;
            default:
                break;
        }
    }


    @Override
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public TimResultMsg register(MsgUserRegisterReqDto reqDto) {
        UserEntity userEntity = iUserService.getByOpenId(reqDto.getOpenId());
        if (userEntity != null) {
            return null;
        }
        userEntity = new UserEntity();
        userEntity.setOpenId(reqDto.getOpenId());
        userEntity.setUid(OpenCodeUtils.generateUserId(reqDto.getRole()));
        if (userEntity.getUid().startsWith("pat")) {
            userEntity.setTargetUid(serviceUid);
            userEntity.setTargetUpdateTime(LocalDateTime.now());
        }
        userEntity.setUserRole(reqDto.getRole());
        userEntity.setCreateBy("system");
        userEntity.setCreateTime(LocalDateTime.now());

        if (userEntity.getUserRole() == 2) {

        } else if (userEntity.getUserRole() == 1) {
            reqDto.setFaceUrl("https://upload.weiheyixue.com/guidance/xh/1537268615155218.png");
            userEntity.setHeaderUrl("https://upload.weiheyixue.com/guidance/xh/1537268615155218.png");
            userEntity.setName("李小毅");
        }
        // im系统注册用户
        TimResultMsg timResultMsg = imSystemUserRegister(userEntity.getUid(), reqDto.getFaceUrl());
        if (timResultMsg.getActionStatus().equals("OK")) {
            iUserService.saveOrUpdate(userEntity);
        }
        return timResultMsg;
    }

    @Override
    public void customerServiceRegister() {
        imSystemUserRegister(serviceUid, "https://upload.weiheyixue.com/robot_avatar%402x.png");
    }

    @Override
    public UserSigRespDto genUserSig() {
        String uid = StpUtil.getLoginIdAsString();
        TLSSigAPIv2 tlsSigAPIv2 = new TLSSigAPIv2(timAppId, timSecret);
        String userSig = null;
        try {
            userSig = tlsSigAPIv2.genUserSig(uid, 604800L);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return UserSigRespDto.builder()
                .uid(uid)
                .userSig(userSig)
                .expire(604800L)
                .build();

    }

    @Override
    public void manualConsultation(String patUid) {
        if (StringUtils.isBlank(patUid)) {
            patUid = StpUtil.getLoginIdAsString();
        }

        UserEntity userEntity = iUserService.validatedEntityByUid(patUid);
        PatientBaseInfoRespDto patientBaseInfoRespDto = hospitalServiceClient.patientBaseInfo(userEntity.getOpenId());
//        UserEntity drEntity = iUserService.getOne(
//                Wrappers.<UserEntity>lambdaQuery()
//                        .eq(UserEntity::getUserRole, 1)
//                        .eq(UserEntity::getDeleted, DeleteEnum.ENABLE.getValue())
//        );
        CloudCustomData cloudCustomData;
        boolean isLastPatFill = StringUtils.isNotBlank(patientBaseInfoRespDto.getLastPatFill());
        UploadUrlRespDto uploadUrlRespDto = asyncService.uploadUrl(patUid);

        boolean isLastPicNeckbu = StringUtils.isNotBlank(patientBaseInfoRespDto.getLastPicNeckbu());
        if (!isLastPicNeckbu) {
            // 颈部B超拍照
            cloudCustomData = CloudCustomData.builder()
                    .type(3)
                    .content("上传图片")
                    .url(uploadUrlRespDto.getUploadPictureUrl())
                    .status(0)
                    .build();
            adminSendMsg(TimAdminSendMsgData.builder()
                    .syncOtherMachine(1)
                    .fromAccount(serviceUid)
                    .toAccount(patUid)
                    .msgLifeTime(604800)
                    .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                    .msgBody(Collections.singletonList(MsgBody.builder()
                            .msgType(MsgTypeEnum.TIMCustomElem.getName())
                            .msgContent(TIMCustomData.builder()
                                    .Data("您好，您还未上传颈部B超照片，不能发起医生咨询，请先完成")
                                    .build())
                            .build()))
                    .cloudCustomData(JSONUtil.toJsonStr(cloudCustomData))
                    .build());

        }

        boolean isLastPicSurgReport = StringUtils.isNotBlank(patientBaseInfoRespDto.getLastPicSurgReport());
        String lastIsSurg = patientBaseInfoRespDto.getLastIsSurg();
        if (!isLastPicSurgReport && lastIsSurg.equals("yes")) {
            // 手术记录报告
            cloudCustomData = CloudCustomData.builder()
                    .type(4)
                    .content("上传图片")
                    .url(uploadUrlRespDto.getUploadPictureUrl())
                    .status(0)
                    .build();

            adminSendMsg(TimAdminSendMsgData.builder()
                    .syncOtherMachine(1)
                    .fromAccount(serviceUid)
                    .toAccount(patUid)
                    .msgLifeTime(604800)
                    .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                    .msgBody(Collections.singletonList(MsgBody.builder()
                            .msgType(MsgTypeEnum.TIMCustomElem.getName())
                            .msgContent(TIMCustomData.builder()
                                    .Data("您好，您还未上传手术记录报告，不能发起医生咨询，请先完成")
                                    .build())
                            .build()))
                    .cloudCustomData(JSONUtil.toJsonStr(cloudCustomData))
                    .build());
        }
        // 更新历史记录中数据上传状态
        List<MsgRecordEntity> msgRecordEntityList = iMsgRecordService.list(
                Wrappers.<MsgRecordEntity>lambdaQuery()
                        .eq(MsgRecordEntity::getUpdateStatus, 0)
                        .isNotNull(MsgRecordEntity::getCloudCustomData)
                        .eq(MsgRecordEntity::getToUid, patUid)
        );
        if (msgRecordEntityList.size() > 0) {
            msgRecordEntityList.forEach(i -> {
                if (i.getToUid().equals(userEntity.getUid())) {
                    boolean needUpdate = false;
                    CloudCustomData customData = JSONUtil.toBean(i.getCloudCustomData(), CloudCustomData.class);
                    switch (customData.getType()) {
                        case 2:
                            // 问卷
                            if (isLastPatFill) {
                                customData.setStatus(1);
                                needUpdate = true;
                            }
                            break;
                        case 3:
                            // 颈部B超拍照
                            if (isLastPicNeckbu) {
                                customData.setStatus(1);
                                needUpdate = true;
                            }
                            break;
                        case 4:
                            // 手术记录报告
                            if (isLastPicSurgReport) {
                                customData.setStatus(1);
                                needUpdate = true;
                            }
                            break;
                        default:
                    }
                    if (needUpdate) {
                        i.setUpdateStatus(1);
                        i.setCloudCustomData(JSONUtil.toJsonStr(customData));
                    }
                }
            });
            iMsgRecordService.updateBatchById(msgRecordEntityList);
        }
        // 开启人工咨询
        if (isLastPatFill && isLastPicNeckbu && (isLastPicSurgReport || lastIsSurg.equals("no"))) {
            startManualConsultation(userEntity);
        } else if (thirdDebug) {
            startManualConsultation(userEntity);
        }
    }

    private void startManualConsultation(UserEntity userEntity) {
        UserEntity dr = iUserService.getOne(
                Wrappers.<UserEntity>lambdaQuery()
                        .eq(UserEntity::getUserRole, 1)
        );
        userEntity.setTargetUid(dr.getUid());
        userEntity.setUpdateBy("system");
        userEntity.setUpdateTime(LocalDateTime.now());
        iUserService.saveOrUpdate(userEntity);
        Map<String, Object> map = new HashMap<>();
        map.put("Text", "系统正在为您转接人工咨询，请耐心等待….您可以描述下您的问题，以便我们更好的为您解答");
        adminSendMsg(TimAdminSendMsgData.builder()
                .syncOtherMachine(1)
                .fromAccount(serviceUid)
                .toAccount(userEntity.getUid())
                .msgLifeTime(604800)
                .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                .msgBody(Collections.singletonList(MsgBody.builder()
                        .msgType(MsgTypeEnum.TIMTextElem.getName())
                        .msgContent(map)
                        .build()))
                .build());

    }


    private void callbackAfterSendMsg(CallbackAfterSendMsgBo callbackAfterSendMsgBo) {

        UserEntity userEntity;
        if (callbackAfterSendMsgBo.getTo_Account().startsWith("pat")) {
            userEntity = iUserService.validatedEntityByUid(callbackAfterSendMsgBo.getTo_Account());
        } else {
            userEntity = iUserService.validatedEntityByUid(callbackAfterSendMsgBo.getFrom_Account());
        }
        String patOpenId = userEntity.getOpenId();
        if (callbackAfterSendMsgBo.getTo_Account().equals(serviceUid)) {
            // 根据用户target_uid修改消息接收方
            Map<String, Object> msgBody = callbackAfterSendMsgBo.getMsgBody().get(0);
            if (String.valueOf(msgBody.get("MsgType")).equals(MsgTypeEnum.TIMTextElem.getName())) {
                String msgContent = String.valueOf(msgBody.get("MsgContent"));
                String text = JSONUtil.parseObj(msgContent).getStr("Text");
                // 如果target_uid为医生 将消息转发给医生
                if (isRetrurnCustomMsg(text, callbackAfterSendMsgBo.getFrom_Account())) {
                    return;
                }
            }
            if (userEntity.getTargetUid().startsWith("dr")) {
                updateMsgToAccount(callbackAfterSendMsgBo, userEntity);
                return;
            }
        }

        // 保存聊天记录
        MsgRecordEntity msgRecordEntity = saveMsgEntity(callbackAfterSendMsgBo, patOpenId);

        // 引导用户明确疾病
        processUserSendThyroidSymptomAnswer(msgRecordEntity, userEntity);

        // 用户注册 随访登记消息
        boolean needNextStep = registerAndFollowUpMsg(msgRecordEntity, userEntity);
        if (!needNextStep) {
            return;
        }

        // 根据消息内容客服回复或微信通知
        customerServiceReplay(msgRecordEntity, callbackAfterSendMsgBo.getFrom_Account(), callbackAfterSendMsgBo.getTo_Account(), userEntity);

        // 医生向患者发送自定义消息
        if (callbackAfterSendMsgBo.getTo_Account().startsWith("pat") && callbackAfterSendMsgBo.getFrom_Account().startsWith("dr")
                && String.valueOf(callbackAfterSendMsgBo.getMsgBody().get(0).get("MsgType")).equals(MsgTypeEnum.TIMCustomElem.getName())
                && StringUtils.isNotBlank(callbackAfterSendMsgBo.getCloudCustomData())) {
            CloudCustomData cloudCustomData = JSONUtil.toBean(callbackAfterSendMsgBo.getCloudCustomData(), CloudCustomData.class);
            // 如果自定义消息类型为结束咨询
            if (cloudCustomData.getType() == 6) {
                stopConsult(callbackAfterSendMsgBo.getTo_Account(), "dr_stop");
            }
        }
    }

    private boolean registerAndFollowUpMsg(MsgRecordEntity msgRecordEntity, UserEntity userEntity) {
        boolean nextStep = true;
        // 判断用户是否注册
        if (userEntity.getThyroidSymptom() == 1 && msgRecordEntity.getFromUid().equals(userEntity.getUid())) {
            PatientBaseInfoRespDto patientBaseInfoRespDto = null;
            try {
                patientBaseInfoRespDto = hospitalServiceClient.patientBaseInfo(userEntity.getOpenId());
            } catch (Exception e) {
                // 判断是否发送过注册消息
                MsgRecordEntity registerMsg = iMsgRecordService.getOne(
                        Wrappers.<MsgRecordEntity>lambdaQuery()
                                .eq(MsgRecordEntity::getFromUid, serviceUid)
                                .eq(MsgRecordEntity::getToUid, userEntity.getUid())
                                .ge(MsgRecordEntity::getMsgTime, LocalDate.now())
                                .isNotNull(MsgRecordEntity::getCloudCustomData)
                                .apply("cloud_custom_data ->'$.type' = 13 ")
                );
                if (registerMsg == null) {
                    // 出现异常  用户未注册
                    adminSendMsg(TimAdminSendMsgData.builder()
                            .syncOtherMachine(1)
                            .fromAccount(serviceUid)
                            .toAccount(userEntity.getUid())
                            .msgLifeTime(604800)
                            .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                            .msgBody(Collections.singletonList(MsgBody.builder()
                                    .msgType(MsgTypeEnum.TIMCustomElem.getName())
                                    .msgContent(TIMCustomData.builder()
                                            .Data("请点击下方按钮进行注册")
                                            .build())
                                    .build()))
                            .cloudCustomData(JSONUtil.toJsonStr(CloudCustomData.builder()
                                    .type(13)
                                    .content("点击注册")
                                    .url(asyncService.getRegisterUrl(userEntity.getOpenId(), userEntity.getUid()))
                                    .build()))
                            .build());
                }
                return false;
            }

            if (patientBaseInfoRespDto != null) {
                // 判断用户是否登记随访
                String lastPatFill = patientBaseInfoRespDto.getLastPatCheckin();
                if (StringUtils.isBlank(lastPatFill)) {
                    MsgRecordEntity followUpMsg = iMsgRecordService.getOne(
                            Wrappers.<MsgRecordEntity>lambdaQuery()
                                    .eq(MsgRecordEntity::getToUid, userEntity.getUid())
                                    .eq(MsgRecordEntity::getFromUid, serviceUid)
                                    .ge(MsgRecordEntity::getMsgTime, LocalDate.now())
                                    .isNotNull(MsgRecordEntity::getCloudCustomData)
                                    .apply("cloud_custom_data ->'$.type' = 14 ")
                    );

                    if (followUpMsg == null) {
                        // 问卷/登记随访
                        CloudCustomData cloudCustomData = CloudCustomData.builder()
                                .type(14)
                                .content("点击登记")
                                .url(asyncService.getFollowUpUrl(userEntity.getOpenId(), userEntity.getUid()))
                                .status(2)
                                .build();
                        adminSendMsg(TimAdminSendMsgData.builder()
                                .syncOtherMachine(1)
                                .fromAccount(serviceUid)
                                .toAccount(userEntity.getUid())
                                .msgLifeTime(604800)
                                .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                                .msgBody(Collections.singletonList(MsgBody.builder()
                                        .msgType(MsgTypeEnum.TIMCustomElem.getName())
                                        .msgContent(TIMCustomData.builder()
                                                .Data("请先登记您的就诊信息")
                                                .build())
                                        .build()))
                                .cloudCustomData(JSONUtil.toJsonStr(cloudCustomData))
                                .build());
                        return false;
                    }

                }
            }
        } else {
            return false;
        }
        return nextStep;
    }

    private void processUserSendThyroidSymptomAnswer(MsgRecordEntity msgRecordEntity, UserEntity userEntity) {
        if (msgRecordEntity == null || userEntity == null) {
            return;
        }
        List<MsgBody> msgBodyList = JSONUtil.toList(msgRecordEntity.getMsgBody(), MsgBody.class);
        MsgBody msgBody = msgBodyList.get(0);
        JSONObject jsonObject = JSONUtil.parseObj(msgBody.getMsgContent());
        String msgContent = jsonObject.getStr("Text");
        // 回复语非甲状腺疾病症状
        if (userEntity.getThyroidSymptom() != 1 && msgRecordEntity.getFromUid().equals(userEntity.getUid())) {
            if (!msgContent.contains("甲状腺")
                    && !msgContent.contains("甲功异常")
                    && !msgContent.contains("甲状腺炎")
                    && !msgContent.contains("甲亢")
                    && !msgContent.contains("甲减")) {
                Map<String, Object> map = new HashMap<>();
                map.put("Text", "您好，您回复的内容非甲状腺疾病症状，请先回复一下您当前的甲状腺疾病症状，如发送：有甲状腺结节、有甲状腺肿瘤、甲功异常、甲状腺炎、甲亢、甲减等");
                adminSendMsg(TimAdminSendMsgData.builder()
                        .syncOtherMachine(2)
                        .fromAccount(serviceUid)
                        .toAccount(userEntity.getUid())
                        .msgLifeTime(604800)
                        .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                        .msgBody(Collections.singletonList(MsgBody.builder()
                                .msgType(MsgTypeEnum.TIMTextElem.getName())
                                .msgContent(map)
                                .build()))
                        .build());
            } else {
                userEntity.setThyroidSymptom(1);
                iUserService.updateById(userEntity);
            }
        }


    }

    @Override
    public InitConversationRespDto initConversation() {

        int status = 0;
        return InitConversationRespDto.builder()
                .status(status)
                .doctorInfoUrl("https://b.yicloud.org/dyn2/articleFront/article/articleId/getJump/376")
                .build();


    }

    @Override
    public PageResult<MsgDataRespDtoV2> patientMsgRecordPage(BasePageReqDto reqDto) {
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        // 获取医生头像
        initDrAvatar();
        String patUid = StpUtil.getLoginIdAsString();
        UserEntity userEntity = iUserService.validatedEntityByUid(patUid);

        PatientBaseInfoRespDto patientBaseInfoRespDto = null;
        try {
            patientBaseInfoRespDto = hospitalServiceClient.patientBaseInfo(userEntity.getOpenId());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        PatientBaseInfoRespDto finalPatientBaseInfoRespDto = patientBaseInfoRespDto;

        PageResult<MsgDataRespDtoV2> msgDataRespDtoV2PageResult = iMsgRecordService.msgRecordByUid(userEntity, reqDto.getPage(), reqDto.getSize(), SERVICE_AVATAR, DOCTOR_AVATAR);
        executorService.schedule(() -> {
            // 发送问候语询问用户症状
            asyncService.sendSymptomQuestion(userEntity);
            // 发送注册/随访问候语
            asyncService.sendRegisterOrFollowUpMsg(finalPatientBaseInfoRespDto, userEntity);
            // 发送欢迎语
            asyncService.sendGreetingMsg(userEntity);
        }, 1L, TimeUnit.SECONDS);
        // 查询聊天记录
        return msgDataRespDtoV2PageResult;
    }

    @Override
    public PageResult<MsgDataRespDtoV2> msgRecordDoctorPatient(MsgRecordPageReqDto reqDto) {
        // 获取医生头像
        initDrAvatar();
        String uid = StpUtil.getLoginIdAsString();
        UserEntity userEntity = iUserService.validatedEntityByUid(reqDto.getPatientUid());
        String conversationString = uid + "##" + reqDto.getPatientUid();
        MsgConversationEntity msgConversationEntity = iMsgConversationService.getOne(
                Wrappers.<MsgConversationEntity>lambdaQuery()
                        .eq(MsgConversationEntity::getConversationString, conversationString)
        );
        if (msgConversationEntity == null) {
            return PageResult.<MsgDataRespDtoV2>builder().build();
        }
        msgConversationEntity.setUnreadMsgNum(0);
        iMsgConversationService.updateById(msgConversationEntity);
        return iMsgRecordService.msgRecordByConversation(msgConversationEntity.getId(), reqDto.getPage(), reqDto.getSize(), uid, userEntity, SERVICE_AVATAR, DOCTOR_AVATAR);
    }

    @Override
    public PageResult<MsgDataRespDtoV2> msgRecordServicePatient(MsgRecordPageReqDto reqDto) {
        // 获取医生头像
        initDrAvatar();

//        String uid = StpUtil.getLoginIdAsString();
        UserEntity userEntity = iUserService.validatedEntityByUid(reqDto.getPatientUid());
        String conversationString = serviceUid + "##" + reqDto.getPatientUid();
        MsgConversationEntity msgConversationEntity = iMsgConversationService.getOne(
                Wrappers.<MsgConversationEntity>lambdaQuery()
                        .eq(MsgConversationEntity::getConversationString, conversationString)
        );
        if (msgConversationEntity == null) {
            return PageResult.<MsgDataRespDtoV2>builder().build();
        }
        return iMsgRecordService.msgRecordByConversation(msgConversationEntity.getId(), reqDto.getPage(), reqDto.getSize(), serviceUid, userEntity, SERVICE_AVATAR, DOCTOR_AVATAR);
    }

    public void initDrAvatar() {
        if (StringUtils.isBlank(DOCTOR_AVATAR)) {
            UserEntity drEntity = iUserService.getOne(
                    Wrappers.<UserEntity>lambdaQuery()
                            .eq(UserEntity::getUserRole, 1)
                            .eq(UserEntity::getDeleted, DeleteEnum.ENABLE.getValue())
            );
            DOCTOR_AVATAR = drEntity.getHeaderUrl();
        }
    }


    private MsgRecordEntity saveMsgEntity(CallbackAfterSendMsgBo callbackAfterSendMsgBo, String patOpenId) {
        if (!callbackAfterSendMsgBo.getErrorInfo().equals("send msg succeed")) {
            return null;
        }
        String conversationString;
        if (callbackAfterSendMsgBo.getTo_Account().startsWith("pat")) {
            conversationString = callbackAfterSendMsgBo.getFrom_Account() + "##" + callbackAfterSendMsgBo.getTo_Account();
        } else {
            conversationString = callbackAfterSendMsgBo.getTo_Account() + "##" + callbackAfterSendMsgBo.getFrom_Account();
        }
        // 查询会话id
        MsgConversationEntity msgConversationEntity = iMsgConversationService.getOne(
                Wrappers.<MsgConversationEntity>lambdaQuery()
                        .eq(MsgConversationEntity::getConversationString, conversationString)
        );
        if (msgConversationEntity == null) {
            msgConversationEntity = new MsgConversationEntity();
            msgConversationEntity.setCreateBy("system");
            msgConversationEntity.setCreateTime(LocalDateTime.now());
            msgConversationEntity.setConversationString(conversationString);
            iMsgConversationService.save(msgConversationEntity);
        }
        // 新增一条聊天记录
        List<MsgBody> msgBody = callbackAfterSendMsgBo.getMsgBody().stream().map(item -> MsgBody.builder()
                .msgType(String.valueOf(item.get("MsgType")))
                .msgContent(item.get("MsgContent"))
                .build()).collect(Collectors.toList());

        MsgRecordEntity msgRecordEntity = new MsgRecordEntity();
        msgRecordEntity.setConversationId(msgConversationEntity.getId());
        msgRecordEntity.setFromUid(callbackAfterSendMsgBo.getFrom_Account());
        msgRecordEntity.setMsgSeq(callbackAfterSendMsgBo.getMsgSeq());
        msgRecordEntity.setMsgRandom(callbackAfterSendMsgBo.getMsgRandom());
        msgRecordEntity.setUnreadMsgNum(callbackAfterSendMsgBo.getUnreadMsgNum());
        msgRecordEntity.setTimeStamp(callbackAfterSendMsgBo.getMsgTime());
        msgRecordEntity.setToUid(callbackAfterSendMsgBo.getTo_Account());
        msgRecordEntity.setMsgKey(callbackAfterSendMsgBo.getMsgKey());
        msgRecordEntity.setMsgBody(JSONUtil.toJsonStr(msgBody));
        // 查询并更新数据上传状态
        if (StringUtils.isNotBlank(callbackAfterSendMsgBo.getCloudCustomData())) {
            CloudCustomData cloudCustomData = JSONUtil.toBean(callbackAfterSendMsgBo.getCloudCustomData(), CloudCustomData.class);
            if (cloudCustomData.getType() == 2 || cloudCustomData.getType() == 3 || cloudCustomData.getType() == 4) {
                PatientBaseInfoRespDto patientBaseInfoRespDto = hospitalServiceClient.patientBaseInfo(patOpenId);
                switch (cloudCustomData.getType()) {
                    case 2:
                        // 问卷
                        boolean isLastPatFill = StringUtils.isNotBlank(patientBaseInfoRespDto.getLastPatFill());
                        if (isLastPatFill) {
                            cloudCustomData.setStatus(1);
                        }
                        break;
                    case 3:
                        // 颈部B超拍照
                        boolean isLastPicNeckbu = StringUtils.isNotBlank(patientBaseInfoRespDto.getLastPicNeckbu());
                        if (isLastPicNeckbu) {
                            cloudCustomData.setStatus(1);
                        }
                        break;
                    case 4:
                        // 手术记录报告
                        boolean isLastPicSurgReport = StringUtils.isNotBlank(patientBaseInfoRespDto.getLastPicSurgReport());
                        if (isLastPicSurgReport) {
                            cloudCustomData.setStatus(1);
                        }
                        break;
                    default:
                        break;
                }
                msgRecordEntity.setUpdateStatus(cloudCustomData.getStatus());
            }
            msgRecordEntity.setCloudCustomData(JSONUtil.toJsonStr(cloudCustomData));
        }
        msgRecordEntity.setMsgTime(LocalDateTime.ofEpochSecond(callbackAfterSendMsgBo.getMsgTime(), 0, ZoneOffset.ofHours(8)));
        msgRecordEntity.setCreateBy("callback");
        msgRecordEntity.setCreateTime(LocalDateTime.now());
        iMsgRecordService.save(msgRecordEntity);

        // 更新会话
        msgConversationEntity.setRecentMsgTime(LocalDateTime.ofEpochSecond(callbackAfterSendMsgBo.getMsgTime(), 0, ZoneOffset.ofHours(8)));
        msgConversationEntity.setRecentMsgId(msgRecordEntity.getId());
        if (msgRecordEntity.getToUid().startsWith("dr")) {
            int oldUnreadNum = msgConversationEntity.getUnreadMsgNum() == null ? 0 : msgConversationEntity.getUnreadMsgNum();
            msgConversationEntity.setUnreadMsgNum(oldUnreadNum + 1);
        }
        iMsgConversationService.saveOrUpdate(msgConversationEntity);
        return msgRecordEntity;
    }

    public void adminSendMsg(TimAdminSendMsgData timAdminSendMsgData) {
        String baseUrl = getEncodeUrl(BASE_ADMIN_SEND_MSG_URL, timAppId, timSecret);
        Map<String, Object> paramsMap = new HashMap<>();
        if (timAdminSendMsgData.getForbidCallbackControl() != null) {
            paramsMap.put("ForbidCallbackControl", timAdminSendMsgData.getForbidCallbackControl());
        }
        paramsMap.put("From_Account", timAdminSendMsgData.getFromAccount());
        paramsMap.put("To_Account", timAdminSendMsgData.getToAccount());
        paramsMap.put("SyncOtherMachine", timAdminSendMsgData.getSyncOtherMachine());
        paramsMap.put("MsgRandom", timAdminSendMsgData.getMsgRandom());
        List<Map<String, Object>> msgBodyList = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("MsgType", timAdminSendMsgData.getMsgBody().get(0).getMsgType());
        map.put("MsgContent", timAdminSendMsgData.getMsgBody().get(0).getMsgContent());
        msgBodyList.add(map);
        paramsMap.put("MsgBody", msgBodyList);
        paramsMap.put("CloudCustomData", timAdminSendMsgData.getCloudCustomData());
        String respStr = RemoteUtils.sendPost(baseUrl, paramsMap);
        TimResultMsg timResultMsg = JSONUtil.toBean(respStr, TimResultMsg.class);
    }

    private void customerServiceReplayMsg(MsgRecordEntity msgRecordEntity) {
        String patientUid = msgRecordEntity.getFromUid();
        List<MsgBody> msgBodyList = JSONUtil.toList(msgRecordEntity.getMsgBody(), MsgBody.class);
        MsgBody msgBody = msgBodyList.get(0);
        if (msgBody.getMsgType().equals(MsgTypeEnum.TIMTextElem.getName())) {
            JSONObject jsonObject = JSONUtil.parseObj(msgBody.getMsgContent());
            String msgContent = jsonObject.getStr("Text");

            if (isRetrurnCustomMsg(msgContent, patientUid)) {
                return;
            }

            List<UserServiceWordEntity> matchWordEntityList = getSimilarityServiceKeyWord(msgContent);
            // 获取匹配度最高的回复语
            UserServiceWordEntity wordEntity = getServiceReplayMsg(matchWordEntityList, patientUid);
            if (null != wordEntity && wordEntity.getPreCondition() == 7) {
                // 人工咨询 返回自定义消息
                adminSendMsg(TimAdminSendMsgData.builder()
                        .syncOtherMachine(1)
                        .fromAccount(serviceUid)
                        .toAccount(patientUid)
                        .msgLifeTime(604800)
                        .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                        .msgBody(Collections.singletonList(MsgBody.builder()
                                .msgType(MsgTypeEnum.TIMCustomElem.getName())
                                .msgContent(TIMCustomData.builder()
                                        .Data("猜你想问")
                                        .build())
                                .build()))
                        .cloudCustomData(JSONUtil.toJsonStr(CloudCustomData.builder()
                                .type(1)
                                .content("人工咨询")
                                .build()))
                        .build());
            } else {
                // 客服向用户发送消息
                Map<String, Object> contentMap = new HashMap<>();
                if (null != wordEntity) {
                    contentMap.put("Text", wordEntity.getContent());
                } else {
                    contentMap.put("Text", "您好，小甲没能理解您的问题，可以简要描述一下您的问题吗？例如发送“挂号、改约、申请复诊、甲状腺癌预后效果、甲状腺癌要马上手术吗”等");
                }
                adminSendMsg(TimAdminSendMsgData.builder()
                        .syncOtherMachine(1)
                        .fromAccount(serviceUid)
                        .toAccount(patientUid)
                        .msgLifeTime(604800)
                        .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                        .msgBody(Collections.singletonList(MsgBody.builder()
                                .msgType(MsgTypeEnum.TIMTextElem.getName())
                                .msgContent(contentMap)
                                .build()))
                        .build());
            }
        }


    }

    private Boolean isRetrurnCustomMsg(String msgContent, String patientUid) {
        boolean r = false;
        switch (msgContent) {
            case "专家介绍":
                adminSendMsg(TimAdminSendMsgData.builder()
                        .syncOtherMachine(1)
                        .fromAccount(serviceUid)
                        .toAccount(patientUid)
                        .msgLifeTime(604800)
                        .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                        .msgBody(Collections.singletonList(MsgBody.builder()
                                .msgType(MsgTypeEnum.TIMCustomElem.getName())
                                .msgContent(TIMCustomData.builder()
                                        .Data("专家介绍")
                                        .build())
                                .build()))
                        .cloudCustomData(JSONUtil.toJsonStr(CloudCustomData.builder()
                                .type(8)
                                .content("专家介绍")
                                .data(JSONUtil.toJsonStr(DoctorInfoRespDto.builder()
                                        .drName("李小毅")
                                        .hospName("北京协和医院")
                                        .title("主任医师 教授 博士生导师")
                                        .position("教授")
                                        .professionalHistory("近10年来，任先后承担了有关家族性甲状腺癌致病基因鉴定、胃癌新辅助化疗的临床研究、家族性胃癌的基础研究等课题。发表各类文章40余篇；参与编写了复发转移性分化型甲状腺癌诊治共识、甲状腺癌患者教育手册等。")
                                        .socialService("现任CSCO甲状腺癌专家委员会委员，中国医学促进会甲状腺疾病分会委员会委员，美国甲状腺协会会员，《中华临床医师》杂志专家委员会青年委员，《中华外科杂志》、《中国全科医学》、《中国肿瘤临床》杂志审稿专家。")
                                        .skill("目前专业方向主要集中在甲状腺疾病、胃癌的手术及综合治疗等方面，努力提倡、并开展了规范的甲状腺癌、胃癌的手术、及综合治疗模式，在胃癌综合治疗和晚期、复杂甲状腺癌的手术及综合治疗方面积累了较丰富的经验。")
                                        .publicationTime("发布于2018-01-04 11:34:41")
                                        .drHeadUrl("https://upload.weiheyixue.com/guidance/xh/1537268615155217.png")
                                        .build()))
                                .build()))
                        .build());
                r = true;
                break;
            case "出诊时间":
                adminSendMsg(TimAdminSendMsgData.builder()
                        .syncOtherMachine(1)
                        .fromAccount(serviceUid)
                        .toAccount(patientUid)
                        .msgLifeTime(604800)
                        .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                        .msgBody(Collections.singletonList(MsgBody.builder()
                                .msgType(MsgTypeEnum.TIMCustomElem.getName())
                                .msgContent(TIMCustomData.builder()
                                        .Data("出诊时间")
                                        .build())
                                .build()))
                        .cloudCustomData(JSONUtil.toJsonStr(CloudCustomData.builder()
                                .type(9)
                                .content("出诊时间")
                                .data(JSONUtil.toJsonStr(patientService.outpatientServiceInfo(patientUid)))
                                .build()))
                        .build());
                r = true;
                break;
            case "就诊须知":
                adminSendMsg(TimAdminSendMsgData.builder()
                        .syncOtherMachine(1)
                        .fromAccount(serviceUid)
                        .toAccount(patientUid)
                        .msgLifeTime(604800)
                        .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                        .msgBody(Collections.singletonList(MsgBody.builder()
                                .msgType(MsgTypeEnum.TIMCustomElem.getName())
                                .msgContent(TIMCustomData.builder()
                                        .Data("就诊须知")
                                        .build())
                                .build()))
                        .cloudCustomData(JSONUtil.toJsonStr(CloudCustomData.builder()
                                .type(10)
                                .content("就诊须知")
                                .data(JSONUtil.toJsonStr(patientService.medicalAdvice()))
                                .build()))
                        .build());
                r = true;
                break;

        }
        return r;
    }

    private void customerServiceReplay(MsgRecordEntity msgRecordEntity, String fromAccount, String toAccount, UserEntity userEntity) {
        if (msgRecordEntity == null || userEntity == null || userEntity.getThyroidSymptom() != 1) {
            return;
        }

        if (toAccount.equals(serviceUid)) {
            String cloudCustomDataStr = msgRecordEntity.getCloudCustomData();
            boolean needServiceReplay = true;
            // 开启人工服务信息 不需要查询客服回复语
            if (StringUtils.isNotBlank(cloudCustomDataStr)) {
                CloudCustomData cloudCustomData = JSONUtil.toBean(cloudCustomDataStr, CloudCustomData.class);
                if (cloudCustomData.getType() == 5) {
                    // 开启人工服务
                    manualConsultation(fromAccount);
                    needServiceReplay = false;
                }
            }
            // 客服回复
            if (needServiceReplay) {
                customerServiceReplayMsg(msgRecordEntity);
            }
        } else {
            // 查询接收方在线状态 如果不在线 发送微信消息
            try {
                sendWxMsgByUid(toAccount);
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }

    }

    private UserServiceWordEntity getServiceReplayMsg(List<UserServiceWordEntity> wordEntityList, String patientUid) {
        if (wordEntityList.isEmpty()) {
            return null;
        }
        if (wordEntityList.size() > 1) {
            UserEntity userEntity = iUserService.validatedEntityByUid(patientUid);
            List<UserServiceWordEntity> filterList = wordEntityList.stream().filter(e -> null != e.getPreCondition() && e.getPreCondition() > 0).collect(Collectors.toList());
            PatientBaseInfoRespDto patientBaseInfoRespDto;
            UserServiceWordEntity wordEntity = null;
            try {
                patientBaseInfoRespDto = hospitalServiceClient.patientBaseInfo(userEntity.getOpenId());
            } catch (Exception e) {
                wordEntity = new UserServiceWordEntity();
                wordEntity.setPreCondition(0);
                wordEntity.setContent("您好，小甲未查到您的就诊信息，您可以使用\"北京协和医院＂App,进行预约检查");
                return wordEntity;
            }
            Integer preCondition = 0;
            if (filterList.size() > 0) {
                preCondition = filterList.get(0).getPreCondition();
            }
            // TODO AI导诊回答内容
            switch (preCondition) {
                case 1:
                case 2:
                    String notNextAppoint = patientBaseInfoRespDto.getNotNextAppoint();
                    if (StringUtils.isNotBlank(notNextAppoint) && notNextAppoint.equals("yes")) {
                        wordEntity = Objects.requireNonNull(wordEntityList.stream().filter(i -> i.getPreCondition() == 1).findFirst().orElse(null));
                    } else {
                        wordEntity = Objects.requireNonNull(wordEntityList.stream().filter(i -> i.getPreCondition() == 2).findFirst().orElse(null));
                    }
                    break;
                case 3:
                case 4:
                    String nextAppointDateStr = patientBaseInfoRespDto.getNextAppointDate();
                    if (StringUtils.isNotBlank(nextAppointDateStr)) {
                        LocalDateTime nextAppointDate = LocalDateTimeUtil.parse(nextAppointDateStr, DatePattern.NORM_DATE_PATTERN);
                    }
                    break;
                case 5:
                case 6:
                    patientBaseInfoRespDto = hospitalServiceClient.patientBaseInfo(userEntity.getOpenId());
                    String lastBooking = patientBaseInfoRespDto.getLastBooking();
                    if (StringUtils.isNotBlank(lastBooking)) {
                        try {
                            LocalDateTime nextAppointDate = LocalDateTimeUtil.parse(lastBooking, DatePattern.NORM_DATE_PATTERN);
                            if (nextAppointDate.minusWeeks(2).isAfter(LocalDate.now().atStartOfDay())) {
                                wordEntity = Objects.requireNonNull(wordEntityList.stream().filter(i -> i.getPreCondition() == 5).findFirst().orElse(null));
                            }
                        } catch (Exception e) {
                            log.error(e.getMessage());
                        }
                    } else {
                        wordEntity = new UserServiceWordEntity();
                        wordEntity.setPreCondition(0);
                        wordEntity.setContent("您在复查申请模块中，查询、提交、或修改复诊时间。");
                    }
                    break;

                default:
                    break;
            }
            if (null != wordEntity) {
                return wordEntity;
            }
        }
        return wordEntityList.get(0);


    }

    public List<UserServiceWordEntity> getSimilarityServiceKeyWord(String msgContent) {
        List<UserServiceWordEntity> serviceWordEntityList = iUserServiceWordService.list(
                Wrappers.<UserServiceWordEntity>lambdaQuery()
                        .eq(UserServiceWordEntity::getDeleted, DeleteEnum.ENABLE.getValue())
                        .groupBy(UserServiceWordEntity::getKeyword)
        );
        Map<String, List<UserServiceWordEntity>> keywordMap = new HashMap<>(serviceWordEntityList.size() * 2);
        for (UserServiceWordEntity entity : serviceWordEntityList) {
            if (StringUtils.isEmpty(entity.getKeyword())) {
                continue;
            }
            for (String keyword : entity.getKeyword().split(",")) {
                List<UserServiceWordEntity> contentList = keywordMap.computeIfAbsent(keyword, k -> new ArrayList<>(8));
                contentList.add(entity);
            }
        }
        // 全匹配
        List<String> matchKeywordList = new ArrayList<>(8);
        keywordMap.forEach((k, v) -> {
            if (msgContent.contains(k)) {
                matchKeywordList.add(k);
            }
        });
        if (!matchKeywordList.isEmpty()) {
            String s = matchKeywordList.stream().max(Comparator.comparing(String::length)).get();
            List<String> filterList = matchKeywordList.stream().filter(key -> key.length() == s.length()).collect(Collectors.toList());
            List<UserServiceWordEntity> list = new ArrayList<>(filterList.size());
            for (String key : filterList) {
                List<UserServiceWordEntity> temp = keywordMap.get(key);
                if (null != temp) {
                    list.addAll(temp);
                }
            }
            return list;
        }
        // 先将关键字进行分词匹配 计算匹配度（能匹配上的字符的长度和）
        AtomicReference<String> matchKey = new AtomicReference<>();
        AtomicInteger maxLength = new AtomicInteger(0);
        keywordMap.keySet().forEach(key -> {
            List<String> keys = Arrays.stream(nlpUtils.jieBa(key)).filter(i -> i.length() > 1).collect(Collectors.toList());
            int length = 0;
            for (String k : keys) {
                if (msgContent.contains(k)) {
                    length += k.length();
                }
            }
            if (length > maxLength.get()) {
                maxLength.set(length);
                matchKey.set(key);
            }
        });
        if (maxLength.get() > 0 && null != matchKey.get()) {
            return keywordMap.get(matchKey.get());
        }
        // 将内容分词与关键字分词进行匹配，计算匹配度（能匹配上的字符的长度和）
        matchKey.set(null);
        maxLength.set(0);
        List<String> words = Arrays.stream(nlpUtils.jieBa(msgContent)).filter(i -> i.length() > 1).collect(Collectors.toList());
        if (msgContent.contains("131")) {
            words.add("131");
        }
        keywordMap.keySet().forEach(key -> {
            List<String> keys = Arrays.stream(nlpUtils.jieBa(key)).filter(i -> i.length() > 1).collect(Collectors.toList());
            int length = 0;
            for (String k : keys) {
                for (String word : words) {
                    if (word.contains(k)) {
                        length += k.length();
                    }
                }
            }
            if (length > maxLength.get()) {
                maxLength.set(length);
                matchKey.set(key);
            }
        });
        if (maxLength.get() > 0 && null != matchKey.get()) {
            return keywordMap.get(matchKey.get());
        }
        return Collections.emptyList();
    }

    private void callbackAfterMsgWithDraw(CallbackAfterMsgWithDrawBo callbackAfterMsgWithDrawBo) {
        MsgRecordEntity msgRecordEntity = iMsgRecordService.getOne(
                Wrappers.<MsgRecordEntity>lambdaQuery()
                        .eq(MsgRecordEntity::getMsgKey, callbackAfterMsgWithDrawBo.getMsgKey())
        );
        if (msgRecordEntity != null) {
            msgRecordEntity.setDeleted(DeleteEnum.UNABLE.getValue());
            msgRecordEntity.setUpdateBy("callback");
            msgRecordEntity.setUpdateTime(LocalDateTime.now());
            iMsgRecordService.updateById(msgRecordEntity);
        }
    }

    private void callbackStateChange(CallbackStateChangeBo callbackStateChangeBo) {
        UserEntity userEntity = iUserService.validatedEntityByUid(callbackStateChangeBo.getInfo().getTo_Account());
        userEntity.setStatus(callbackStateChangeBo.getInfo().getAction());
        userEntity.setUpdateBy("callback");
        userEntity.setUpdateTime(LocalDateTime.now());
        iUserService.updateById(userEntity);
    }

    private void callbackAfterMsgReport(CallbackAfterMsgReportBo callbackAfterMsgReportBo) {
        String peerAccount = callbackAfterMsgReportBo.getPeer_Account();
        if (peerAccount.startsWith("dr")) {
            String getConversationString = peerAccount + callbackAfterMsgReportBo.getReport_Account();
            MsgConversationEntity conversationEntity = iMsgConversationService.getOne(
                    Wrappers.<MsgConversationEntity>lambdaQuery()
                            .eq(MsgConversationEntity::getConversationString, getConversationString)
            );
            if (conversationEntity != null) {
                conversationEntity.setUnreadMsgNum(0);
                iMsgConversationService.updateById(conversationEntity);
            }
        }
    }

    private void stopConsult(String toAccount, String type) {
        if (StringUtils.isBlank(toAccount)) {
            return;
        }
        try {
            // 更新用户target_uid 为机器人
            TimAdminSendMsgData msgData;
            if (type.equals("timeout_stop")) {
                msgData = TimAdminSendMsgData.builder()
                        .syncOtherMachine(2)
                        .fromAccount(serviceUid)
                        .toAccount(toAccount)
                        .msgLifeTime(604800)
                        .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                        .cloudCustomData(JSONUtil.toJsonStr(CloudCustomData.builder()
                                .type(11)
                                .build()))
                        .msgBody(Collections.singletonList(MsgBody.builder()
                                .msgType(MsgTypeEnum.TIMCustomElem.getName())
                                .msgContent(TIMCustomData.builder()
                                        .Data("由于长时间无回复，已结束本次咨询")
                                        .build())
                                .build()))
                        .build();
                adminSendMsg(msgData);
            }
            Map<String, Object> msgContentMap = new HashMap<>();
            msgContentMap.put("Text", "祝您早日康复，再见~");
            msgData = TimAdminSendMsgData.builder()
                    .syncOtherMachine(2)
                    .fromAccount(serviceUid)
                    .toAccount(toAccount)
                    .msgLifeTime(604800)
                    .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                    .msgBody(Collections.singletonList(MsgBody.builder()
                            .msgType(MsgTypeEnum.TIMTextElem.getName())
                            .msgContent(msgContentMap)
                            .build()))
                    .build();
            adminSendMsg(msgData);
            UserEntity userEntity = iUserService.validatedEntityByUid(toAccount);
            userEntity.setUpdateBy("stop_consult");
            userEntity.setUpdateTime(LocalDateTime.now());
            userEntity.setTargetUpdateTime(LocalDateTime.now());
            userEntity.setGreetingMsg(1);
            userEntity.setTargetUid(serviceUid);
            iUserService.updateById(userEntity);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    private void updateMsgToAccount(CallbackAfterSendMsgBo callbackAfterSendMsgBo, UserEntity userEntity) {
        // 如果target_uid为医生 将消息转发给医生
        if (userEntity.getTargetUid().startsWith("dr")) {
            callbackAfterSendMsgBo.setTo_Account(userEntity.getTargetUid());
            List<MsgBody> msgBodyList = callbackAfterSendMsgBo.getMsgBody().stream().map(item -> MsgBody.builder()
                    .msgType(String.valueOf(item.get("MsgType")))
                    .msgContent(item.get("MsgContent"))
                    .build()).collect(Collectors.toList());
            adminSendMsg(TimAdminSendMsgData.builder()
                    .syncOtherMachine(2)
                    .fromAccount(callbackAfterSendMsgBo.getFrom_Account())
                    .toAccount(userEntity.getTargetUid())
                    .msgLifeTime(604800)
                    .msgRandom((long) RandomUtil.randomInt(100000, 1000000))
                    .msgBody(msgBodyList)
                    .build());

            // 查询接收方在线状态 如果不在线 发送微信消息
            try {
                sendWxMsgByUid(callbackAfterSendMsgBo.getTo_Account());
            } catch (Exception e) {
                log.error(e.getMessage());
            }

        }
    }

    public static String getEncodeUrl(String path, Long sdkAppId, String sdkSecret) {
        TLSSigAPIv2 tlsSigAPIv2 = new TLSSigAPIv2(sdkAppId, sdkSecret);
        String sig = null;
        try {
            sig = tlsSigAPIv2.genUserSig("administrator", 604800L);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        String baseUrl = path +
                String.format("sdkappid=%d&identifier=%s&usersig=%s&random=%d&contenttype=%s"
                        , sdkAppId, "administrator", sig, RandomUtil.randomInt(1, 429496729), "json");
        log.info("[发送TIM消息]，baseUrl：{}", baseUrl);
        return baseUrl;
    }

    private void sendWxMsgByUid(String uid) {
        UserEntity userEntity = iUserService.validatedEntityByUid(uid);
        if (!userEntity.getStatus().equals("Login")) {
            String userType = "";
            if (userEntity.getUid().startsWith("dr")) {
                userType = "dr";
            } else if (userEntity.getUid().startsWith("pat")) {
                userType = "pat";
            }
            String patName = null;
            if (userType.equals("pat")) {
                PatientBaseInfoRespDto patientBaseInfoRespDto = hospitalServiceClient.patientBaseInfo(userEntity.getOpenId());
                patName = patientBaseInfoRespDto.getPatName();
            }
            hospitalServiceClient.sendWxMsg(userEntity.getOpenId(), patName, userType);
        }
    }

    private TimResultMsg imSystemUserRegister(String uid, String faceUrl) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("UserID", uid);
        if (StringUtils.isNotBlank(faceUrl)) {
            paramsMap.put("FaceUrl", faceUrl);
        }
        ;
        String baseUrl = getEncodeUrl(BASE_SINGLE_IMPORT_URL, timAppId, timSecret);
        String respStr = RemoteUtils.sendPost(baseUrl, paramsMap);
        TimResultMsg timResultMsg = JSONUtil.toBean(respStr, TimResultMsg.class);
        return timResultMsg;
    }

    @Scheduled(cron = "0 * * * * ?")
    public void stopConsultSchedule() {
        List<UserEntity> userEntityList = iUserService.list(
                Wrappers.<UserEntity>lambdaQuery()
                        .eq(UserEntity::getUserRole, 2)
                        .le(UserEntity::getTargetUpdateTime, LocalDateTime.now().minusMinutes(30))
                        .ne(UserEntity::getTargetUid, serviceUid)
        );
        Map<String, UserEntity> userEntityMap = userEntityList.stream().collect(Collectors.toMap(UserEntity::getUid, i -> i));
        List<MsgConversationEntity> conversationEntityList = iMsgConversationService.list(
                Wrappers.<MsgConversationEntity>lambdaQuery()
                        .notLike(MsgConversationEntity::getConversationString, serviceUid)
                        .le(MsgConversationEntity::getRecentMsgTime, LocalDateTime.now().minusMinutes(30))
        );

        conversationEntityList.forEach(msgConversationEntity -> {
            for (String uid : userEntityMap.keySet()) {
                if (msgConversationEntity.getConversationString().contains(uid)) {
                    UserEntity userEntity = userEntityMap.remove(uid);
                    stopConsult(userEntity.getUid(), "timeout_stop");
                }
            }
        });


    }


}
